;; This file is part of Scheme-GNUnet
;; Copyright © 2022 GNUnet e.V.
;;
;; Scheme-GNUnet is free software: you can redistribute it and/or modify it
;; under the terms of the GNU Affero General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; Scheme-GNUnet is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Affero General Public License for more details.
;;
;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;
;; SPDX-License-Identifier: AGPL-3.0-or-later

;; TODO: document
(define-library (gnu gnunet server)
  (export maybe-send-control-message!* make-error-handler)
  (import (only (rnrs base)
		begin define case else apply values quote)
	  (only (fibers conditions)
		wait-operation)
	  (only (fibers channels)
		put-operation)
	  (only (fibers operations)
		choice-operation perform-operation))
  (begin
    (define (maybe-send-control-message!* terminal-condition control-channel
					  . message)
      "Send @var{message} to the main loop, unless it is stopping or has stopped.

This sends a @var{message} to @var{control-channel} or waits for
@var{terminal-condition} to be signalled, whichever happens first."
      (perform-operation
       (choice-operation
	;; Nothing to do when the <server> is permanently disconnected,
	;; or is being disconnected.
	(wait-operation terminal-condition)
	(put-operation control-channel message))))

    (define (make-error-handler connected disconnected terminal-condition control-channel)
      (define (error-handler key . arguments)
	(case key
	  ((connection:connected)
	   ;; Tell the event loop to resume old requests.
	   (connected)
	   (maybe-send-control-message!* terminal-condition control-channel
					 'resend-old-operations!)
	   (values))
	  ((input:regular-end-of-file input:premature-end-of-file)
	   (disconnected)
	   ;; Tell the event loop that it is time to restart,
	   ;; unless it already stopping.
	   (maybe-send-control-message!* terminal-condition control-channel 'reconnect!))
	  ;; The event loop closed the queue and will exit, nothing to do here!
	  ;;
	  ;; Tested by "(DHT) close, not connected --> all fibers stop,
	  ;; no callbacks called" in tests/distributed-hash-table.scm.
	  ((connection:interrupted)
	   (values))
	  (else
	   ;; Some unknown problem, let the event loop report the error,
	   ;; disconnect and stop reconnecting.  The first two happen
	   ;; in no particular order.
	   (apply maybe-send-control-message!* terminal-condition
		  control-channel 'oops! key arguments)
	   (values))))
      error-handler)))
